home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: sashimi.c 1.9 1999/06/20 10:22:23 olsen Exp olsen $
- *
- * Sashimi -- intercepts raw serial debugging output on your own machine
- *
- * Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
- * Public Domain
- *
- * :ts=4
- */
-
- /****************************************************************************/
-
- #define NULL ((APTR)0UL)
-
- /****************************************************************************/
-
- #include <exec/execbase.h>
- #include <exec/memory.h>
-
- #include <devices/timer.h>
-
- #include <dos/dosextens.h>
- #include <dos/rdargs.h>
-
- #include <clib/timer_protos.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
-
- #include <pragmas/timer_pragmas.h>
- #include <pragmas/exec_sysbase_pragmas.h>
- #include <pragmas/dos_pragmas.h>
-
- #define USE_BUILTIN_MATH
- #include <string.h>
- #include <stddef.h>
- #include <stdio.h>
-
- /****************************************************************************/
-
- STRPTR Version = "$VER: Sashimi 1.6 (20.6.99)\r\n";
-
- /****************************************************************************/
-
- #define OK (0)
- #define NOT !
- #define BUSY NULL
- #define ZERO ((BPTR)0UL)
-
- /****************************************************************************/
-
- enum
- {
- MODE_Regular,
- MODE_Recovery
- };
-
- /****************************************************************************/
-
- #define MILLION 1000000
-
- /****************************************************************************/
-
- STATIC struct Device * TimerBase;
-
- /****************************************************************************/
-
- extern struct Library * SysBase;
- extern struct Library * DOSBase;
-
- /****************************************************************************/
-
- typedef LONG SWITCH;
- typedef LONG * NUMBER;
- typedef STRPTR KEY;
-
- STATIC struct
- {
- /* Startup options */
- KEY Recover; /* Recover any old Sashimi buffer still in memory */
- SWITCH On; /* Ignored */
- NUMBER BufferK; /* Buffer size, to the power of two */
- NUMBER BufferSize; /* Buffer size in bytes */
- SWITCH NoPrompt; /* Do not show the initial prompt message */
- SWITCH Quiet; /* Do not produce any output at all */
- SWITCH AskExit; /* Ask whether to exit the program */
- SWITCH AskSave; /* Ask for a file to save the buffer to when exiting */
- SWITCH TimerOn; /* Check the circular buffer every 1/10 of a second */
- SWITCH Console; /* Open a console window for I/O */
- KEY Window; /* Console window specifier */
-
- /* Runtime options */
- SWITCH Off; /* Turn Sashimi off */
- SWITCH Save; /* Save the circular buffer contents */
- KEY SaveAs; /* Save the circular buffer contents under a specific name */
- SWITCH Empty; /* Empty the circular buffer */
- } ShellArguments;
-
- STATIC const STRPTR ShellTemplate =
- "RECOVER/K,"
- "ON/S,"
- "BUFK/N,"
- "BUFFERSIZE/N,"
- "NOPROMPT/S,"
- "QUIET/S,"
- "ASKEXIT/S,"
- "ASKSAVE/S,"
- "TIMERON/S,"
- "CONSOLE/S,"
- "WINDOW/K,"
- "OFF/S,"
- "SAVE/S,"
- "SAVEAS/K,"
- "EMPTY/S";
-
- /****************************************************************************/
-
- /* Eat me */
- #define COOKIE 0x08021999
-
- struct SashimiResource
- {
- struct Library sr_Library; /* Global link */
- UWORD sr_Pad; /* Long word alignment */
-
- ULONG sr_Cookie; /* Magic marker */
- APTR sr_PointsToCookie; /* Points back to cookie */
- ULONG sr_CreatedWhen; /* When exactly was this data structure created? */
-
- struct Task * sr_Owner; /* Current owner of the patches */
- LONG sr_OwnerSigBit;
- ULONG sr_OwnerSigMask; /* Signal mask to send when a new line is in the buffer. */
-
- ULONG sr_FIFOTotalSize; /* Number of bytes allocated for the buffer */
- ULONG sr_FIFOReadIndex; /* Read index counter */
- ULONG sr_FIFOWriteIndex; /* Write index counter */
- ULONG sr_FIFOBytesStored; /* Number of bytes in the FIFO */
- BOOL sr_FIFOOverrun; /* TRUE if the write index counter has
- * overrun the read index counter.
- */
- BOOL sr_FIFOWrapped; /* TRUE if the write index counter has
- * wrapped around the circular buffer.
- */
- UBYTE sr_FIFO[1]; /* The message buffer */
- };
-
- STATIC const STRPTR SashimiResourceName = "sashimi.resource";
- STATIC struct SashimiResource * GlobalSashimiResource;
-
- /****************************************************************************/
-
- extern LONG __far LVORawIOInit;
- extern LONG __far LVORawMayGetChar;
- extern LONG __far LVORawPutChar;
-
- /****************************************************************************/
-
- STATIC APTR OldRawIOInit;
- STATIC APTR OldRawMayGetChar;
- STATIC APTR OldRawPutChar;
-
- /****************************************************************************/
-
- VOID __saveds __asm
- NewRawIOInit(VOID)
- {
- /* Nothing happens here */
- }
-
- LONG __saveds __asm
- NewRawMayGetChar(VOID)
- {
- /* We always return sort of a confirmation. */
- return('y');
- }
-
- /****************************************************************************/
-
- STATIC LONG
- GetCharsInFIFO(struct SashimiResource * sr)
- {
- LONG result;
-
- Disable();
-
- if(sr->sr_FIFOWrapped)
- result = sr->sr_FIFOTotalSize;
- else
- result = sr->sr_FIFOWriteIndex;
-
- Enable();
-
- return(result);
- }
-
- STATIC VOID
- EmptyFIFO(struct SashimiResource * sr)
- {
- Disable();
-
- sr->sr_FIFOReadIndex = 0;
- sr->sr_FIFOWriteIndex = 0;
- sr->sr_FIFOBytesStored = 0;
- sr->sr_FIFOOverrun = FALSE;
- sr->sr_FIFOWrapped = FALSE;
-
- Enable();
- }
-
- STATIC LONG
- ReadFIFOChars(struct SashimiResource * sr,UBYTE * buffer,LONG maxChars)
- {
- LONG result = 0;
-
- Disable();
-
- if(sr->sr_FIFOBytesStored > 0)
- {
- LONG howMany;
-
- if(maxChars > sr->sr_FIFOBytesStored)
- maxChars = sr->sr_FIFOBytesStored;
-
- do
- {
- /* Find out how many characters can be read
- * from the FIFO without overrunning the
- * end of it. We don't read more than these
- * few characters in one go.
- */
- howMany = min(maxChars,sr->sr_FIFOTotalSize - sr->sr_FIFOReadIndex);
-
- memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOReadIndex],howMany);
-
- result += howMany;
- buffer += howMany;
- maxChars -= howMany;
-
- sr->sr_FIFOReadIndex = (sr->sr_FIFOReadIndex + howMany) % sr->sr_FIFOTotalSize;
- }
- while(maxChars > 0);
-
- /* Subtract the number of characters we
- * read in the loop.
- */
- sr->sr_FIFOBytesStored -= result;
- }
-
- Enable();
-
- return(result);
- }
-
- STATIC VOID
- StoreFIFOChar(struct SashimiResource * sr,UBYTE c)
- {
- sr->sr_FIFO[sr->sr_FIFOWriteIndex] = c;
- sr->sr_FIFOWriteIndex = (sr->sr_FIFOWriteIndex + 1) % sr->sr_FIFOTotalSize;
-
- /* If the buffer wraps around, remember it. */
- if(sr->sr_FIFOWriteIndex == 0)
- sr->sr_FIFOWrapped = TRUE;
-
- /* Check if the circular buffer was overrun */
- sr->sr_FIFOBytesStored++;
- if(sr->sr_FIFOBytesStored > sr->sr_FIFOTotalSize)
- {
- sr->sr_FIFOOverrun = TRUE;
-
- /* Move the read index to the same position as
- * the write index and retain only as many
- * bytes as would fit into the FIFO.
- */
- sr->sr_FIFOReadIndex = sr->sr_FIFOWriteIndex;
- sr->sr_FIFOBytesStored = sr->sr_FIFOTotalSize;
- }
- }
-
- /****************************************************************************/
-
- VOID __saveds __asm
- NewRawPutChar(register __d0 UBYTE c)
- {
- /* Do not store NUL bytes. */
- if(c != '\0')
- {
- STATIC ULONG Position = 0;
-
- Disable();
-
- /* Filter out extra <cr> characters. */
- if(c != '\r' || Position > 0)
- {
- struct SashimiResource * sr = GlobalSashimiResource;
-
- /* Store another byte in the buffer */
- StoreFIFOChar(sr,c);
-
- /* Notify Sashimi every time there is an end of line
- * character in the stream.
- */
- if(c == '\n' || c == '\r')
- Signal(sr->sr_Owner,sr->sr_OwnerSigMask);
- }
-
- if(c == '\r' || c == '\n')
- Position = 0;
- else
- Position++;
-
- Enable();
- }
- }
-
- /****************************************************************************/
-
- /* This is in SafeRawPutChar.asm */
- extern VOID __asm SafeRawPutChar(register __d0 UBYTE c);
-
- STATIC VOID
- RemovePatches(VOID)
- {
- APTR res;
-
- /* We disable the interrupts because the raw I/O routines can
- * be called from within interrupt code.
- */
- Disable();
-
- /* For every patch planted, remove it and check whether the code
- * had been patched before. If it has, restore the patch. Note that
- * this is not bullet proof :(
- */
- res = SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())OldRawIOInit);
- if(res != (APTR)NewRawIOInit)
- SetFunction(SysBase,(LONG)&LVORawIOInit,(ULONG (*)())res);
-
- res = SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())OldRawMayGetChar);
- if(res != (APTR)NewRawMayGetChar)
- SetFunction(SysBase,(LONG)&LVORawMayGetChar,(ULONG (*)())res);
-
- res = SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())OldRawPutChar);
- if(res != (APTR)SafeRawPutChar)
- SetFunction(SysBase,(LONG)&LVORawPutChar,(ULONG (*)())res);
-
- Enable();
- }
-
- STATIC VOID
- InstallPatches(VOID)
- {
- /* We disable the interrupts because the raw I/O routines can
- * be called from within interrupt code.
- */
- Disable();
-
- OldRawIOInit = SetFunction(SysBase,(LONG)&LVORawIOInit, (ULONG (*)())NewRawIOInit);
- OldRawMayGetChar = SetFunction(SysBase,(LONG)&LVORawMayGetChar, (ULONG (*)())NewRawMayGetChar);
- OldRawPutChar = SetFunction(SysBase,(LONG)&LVORawPutChar, (ULONG (*)())SafeRawPutChar);
-
- Enable();
- }
-
- /****************************************************************************/
-
- STATIC VOID
- FreeSashimiResource(struct SashimiResource * sr)
- {
- if(sr != NULL)
- {
- FreeSignal(sr->sr_OwnerSigBit);
-
- /* Destroy the markers */
- sr->sr_Cookie = 0;
- sr->sr_PointsToCookie = NULL;
-
- FreeMem(sr,sizeof(*sr) + sr->sr_FIFOTotalSize-1);
- }
- }
-
- STATIC LONG
- RemoveSashimiResource(struct SashimiResource * sr)
- {
- LONG error = OK;
-
- if(sr != NULL)
- {
- Forbid();
-
- /* Allow the resource to be removed only if
- * there are no customers using it.
- */
- if(sr->sr_Library.lib_OpenCnt == 0)
- RemResource(sr);
- else
- error = ERROR_OBJECT_IN_USE;
-
- Permit();
- }
-
- return(error);
- }
-
- STATIC LONG
- AddSashimiResource(ULONG bufferSize,struct SashimiResource ** resourcePtr)
- {
- struct SashimiResource * sr;
- LONG error = OK;
-
- /* We will do something really tricky; to increase our chances of
- * allocating an old Sashimi buffer to be recovered, we allocate
- * the amount of memory needed plus the size of a memory chunk.
- * Then we release that buffer again and reallocate it with the
- * size of the memory chunk trailing behind it.
- */
-
- Forbid();
-
- sr = AllocMem(sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1,MEMF_ANY|MEMF_PUBLIC);
- if(sr != NULL)
- {
- FreeMem(sr,sizeof(struct MemChunk) + sizeof(*sr) + bufferSize-1);
- sr = AllocAbs(sizeof(*sr) + bufferSize-1,(BYTE *)sr + sizeof(struct MemChunk));
- }
-
- Permit();
-
- if(sr != NULL)
- {
- struct timeval now;
-
- GetSysTime(&now);
-
- memset(sr,0,sizeof(*sr)-1);
-
- sr->sr_Library.lib_Node.ln_Name = (char *)SashimiResourceName;
- sr->sr_Library.lib_Node.ln_Type = NT_RESOURCE;
- sr->sr_Owner = FindTask(NULL);
- sr->sr_FIFOTotalSize = bufferSize;
- sr->sr_Cookie = COOKIE;
- sr->sr_PointsToCookie = &sr->sr_Cookie;
- sr->sr_CreatedWhen = now.tv_secs;
-
- sr->sr_OwnerSigBit = AllocSignal(-1);
- if(sr->sr_OwnerSigBit != -1)
- {
- sr->sr_OwnerSigMask = (1UL << sr->sr_OwnerSigBit);
-
- Forbid();
-
- /* Do not add the resource if it has already been installed. */
- if(OpenResource((STRPTR)SashimiResourceName) == NULL)
- AddResource(sr);
- else
- error = ERROR_OBJECT_EXISTS;
-
- Permit();
- }
- else
- {
- error = ERROR_NO_FREE_STORE;
- }
- }
- else
- {
- error = ERROR_NO_FREE_STORE;
- }
-
- if(error != OK)
- {
- FreeSashimiResource(sr);
- sr = NULL;
- }
-
- (*resourcePtr) = sr;
-
- return(error);
- }
-
- /****************************************************************************/
-
- STATIC VOID
- CloseSashimiResource(struct SashimiResource * sr)
- {
- if(sr != NULL)
- {
- Forbid();
-
- sr->sr_Library.lib_OpenCnt--;
-
- Permit();
- }
- }
-
- STATIC struct SashimiResource *
- OpenSashimiResource(VOID)
- {
- struct SashimiResource * sr;
-
- Forbid();
-
- sr = OpenResource((STRPTR)SashimiResourceName);
- if(sr != NULL)
- sr->sr_Library.lib_OpenCnt++;
-
- Permit();
-
- return(sr);
- }
-
- /****************************************************************************/
-
- STATIC LONG
- SaveBuffer(const STRPTR name,struct SashimiResource * sr,LONG mode)
- {
- LONG error = OK;
- STRPTR buffer;
-
- /* We allocate a temporary buffer to store the circular
- * buffer data in.
- */
- buffer = AllocVec(sr->sr_FIFOTotalSize,MEMF_ANY|MEMF_PUBLIC);
- if(buffer != NULL)
- {
- LONG bytesInBuffer;
- BOOL wrapped;
- BOOL overrun;
- BPTR file;
-
- if(mode == MODE_Regular)
- {
- /* Stop interrupts and multitasking for a tick. */
- Disable();
- }
-
- wrapped = sr->sr_FIFOWrapped;
- overrun = sr->sr_FIFOOverrun;
-
- if(wrapped)
- {
- LONG oldBytes = sr->sr_FIFOTotalSize - sr->sr_FIFOWriteIndex;
-
- /* Unwrap the buffer; first copy the old data (following the
- * write index) then the newer data.
- */
- memcpy(buffer,&sr->sr_FIFO[sr->sr_FIFOWriteIndex],oldBytes);
- memcpy(&buffer[oldBytes],sr->sr_FIFO,sr->sr_FIFOWriteIndex);
-
- bytesInBuffer = sr->sr_FIFOTotalSize;
- }
- else
- {
- memcpy(buffer,sr->sr_FIFO,sr->sr_FIFOWriteIndex);
-
- bytesInBuffer = sr->sr_FIFOWriteIndex;
- }
-
- if(mode == MODE_Regular)
- {
- /* Start interrupts and multitasking again. */
- Enable();
- }
-
- /* Write the buffer contents. */
- file = Open((STRPTR)name,MODE_NEWFILE);
- if(file != ZERO)
- {
- if(mode == MODE_Recovery)
- {
- if(FPrintf(file,"RECOVERY WARNING - Data may have been damaged\n") < 0)
- error = IoErr();
- }
-
- if(error == OK && overrun)
- {
- if(FPrintf(file,"BUFFER WAS OVERRUN - Data may have been lost\n") < 0)
- error = IoErr();
- }
-
- if(error == OK && wrapped)
- {
- if(FPrintf(file,"BUFFER WRAPPED - This is the most recent captured data\n\n") < 0)
- error = IoErr();
- }
-
- /* FPrintf() is a buffered I/O routine, this is why we need to flush the
- * output buffer here. Otherwise, it would be flushed after the Write()
- * command below is finished and the file is closed. This is not what
- * we want as that would have the effect of adding the messages above
- * to the end of the file.
- */
- if(error == OK)
- Flush(file);
-
- if(error == OK)
- {
- if(Write(file,buffer,bytesInBuffer) != bytesInBuffer)
- error = IoErr();
- }
-
- Close(file);
- }
- else
- {
- error = IoErr();
- }
-
- FreeVec(buffer);
- }
- else
- {
- error = ERROR_NO_FREE_STORE;
- }
-
- return(error);
- }
-
- /****************************************************************************/
-
- STATIC BOOL
- Recover(const STRPTR fileName)
- {
- struct SashimiResource * sr = NULL;
- APTR allocated = NULL;
- struct MemHeader * mh;
- ULONG * start;
- ULONG * end;
- BOOL success;
-
- Printf("Trying to recover old Sashimi buffer... ");
- Flush(Output());
-
- Forbid();
-
- /* Scan the system memory list. */
- for(mh = (struct MemHeader *)((struct ExecBase *)SysBase)->MemList.lh_Head ;
- mh->mh_Node.ln_Succ != NULL ;
- mh = (struct MemHeader *)mh->mh_Node.ln_Succ)
- {
- start = (ULONG *)mh->mh_Lower;
- end = (ULONG *)mh->mh_Upper;
-
- do
- {
- /* First look for the cookie... */
- if(start[0] == COOKIE)
- {
- /* Then look for the pointer back to it. */
- if(start[1] == (ULONG)start)
- {
- /* Unless we don't have a resource pointer
- * yet, compare the creation times and take
- * only the latest buffer.
- */
- if(sr == NULL || start[2] > sr->sr_CreatedWhen)
- sr = (struct SashimiResource *)((ULONG)start - offsetof(struct SashimiResource,sr_Cookie));
- }
- }
- }
- while(++start != end);
- }
-
- /* Try to allocate the memory the old buffer occupies. */
- if(sr != NULL)
- allocated = AllocAbs(sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk),(BYTE *)sr - sizeof(struct MemChunk));
-
- Permit();
-
- if(sr != NULL)
- {
- LONG error = OK;
- LONG numBytes;
-
- if(sr->sr_FIFOWrapped)
- numBytes = sr->sr_FIFOTotalSize;
- else
- numBytes = sr->sr_FIFOWriteIndex;
-
- Printf("found something (%ld bytes).\n",numBytes);
-
- /* If there is anything worth saving, save it. */
- if(numBytes > 0)
- {
- error = SaveBuffer(fileName,sr,MODE_Recovery);
- if(error == OK)
- Printf("Recovered Sashimi buffer saved as \"%s\".\n",fileName);
- else
- PrintFault(error,fileName);
- }
- else
- {
- Printf("This is not worth saving.\n");
- }
-
- /* If everything went fine so far and
- * if we are the owner of the buffer,
- * mark it as invalid.
- */
- if(error == OK && allocated != NULL)
- {
- sr->sr_Cookie = 0;
- sr->sr_PointsToCookie = NULL;
- }
-
- success = TRUE;
- }
- else
- {
- Printf("sorry.\n");
-
- success = FALSE;
- }
-
- /* Release the buffer... */
- if(allocated != NULL)
- FreeMem(allocated,sizeof(*sr) + sr->sr_FIFOTotalSize-1 + sizeof(struct MemChunk));
-
- return(success);
- }
-
- /****************************************************************************/
-
- int
- main(int argc,char **argv)
- {
- int result = RETURN_FAIL;
-
- /* Kickstart 2.04 and a Shell window are required. */
- if(DOSBase->lib_Version >= 37 && argc > 0)
- {
- struct RDArgs * rdargs;
-
- rdargs = ReadArgs((STRPTR)ShellTemplate,(LONG *)&ShellArguments,NULL);
- if(rdargs != NULL)
- {
- /* Before anything else happens, check if
- * we should recover any old data.
- */
- if(ShellArguments.Recover != NULL)
- {
- if(Recover(ShellArguments.Recover))
- result = RETURN_OK;
- else
- result = RETURN_WARN;
- }
- else
- {
- struct SashimiResource * sr = NULL;
- struct MsgPort * timePort;
- struct timerequest * timeRequest = NULL;
- BOOL added = FALSE;
- BOOL opened = FALSE;
- LONG error = OK;
- BPTR oldOutput = ZERO;
- BPTR newOutput = ZERO;
- BPTR oldInput = ZERO;
- BPTR newInput = ZERO;
- struct MsgPort * oldConsoleTask = NULL;
- STRPTR saveFile;
-
- /* Fill in the save file name, we might need it later. */
- if(ShellArguments.SaveAs != NULL)
- saveFile = ShellArguments.SaveAs;
- else
- saveFile = "T:sashimi.out";
-
- /* Set up the timer.device interface. */
- timePort = CreateMsgPort();
- if(timePort != NULL)
- {
- timeRequest = (struct timerequest *)CreateIORequest(timePort,sizeof(*timeRequest));
- if(timeRequest != NULL)
- {
- if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)timeRequest,0) == OK)
- TimerBase = timeRequest->tr_node.io_Device;
- else
- error = ERROR_NO_FREE_STORE; /* Misleading? */
- }
- else
- {
- error = ERROR_NO_FREE_STORE;
- }
- }
- else
- {
- error = ERROR_NO_FREE_STORE;
- }
-
- if(error == OK)
- {
- /* Try to open the resource, and if that fails, create one. */
- sr = OpenSashimiResource();
- if(sr != NULL)
- {
- opened = TRUE;
- }
- else
- {
- ULONG bufferSize;
-
- /* The default buffer size is 32K. */
- bufferSize = 32 * 1024;
-
- /* Check for a specific buffer size (power of two). */
- if(ShellArguments.BufferK != NULL)
- bufferSize = 1024 * (*ShellArguments.BufferK);
-
- /* Check for a specific buffer size. */
- if(ShellArguments.BufferSize != NULL)
- bufferSize = (ULONG)(*ShellArguments.BufferSize);
-
- /* Don't make the buffer too small. */
- if(bufferSize < 4096)
- bufferSize = 4096;
-
- /* Add the resource to the public list. Note that
- * the patches are not installed yet.
- */
- error = AddSashimiResource(bufferSize,&sr);
- if(error == OK)
- added = TRUE;
- }
- }
-
- /* Did we get everything we wanted? */
- if(error != OK)
- {
- PrintFault(error,"Sashimi");
- result = RETURN_ERROR;
- }
- else
- {
- if(opened)
- {
- /* Save the current circular buffer contents? */
- if(ShellArguments.SaveAs != NULL || ShellArguments.Save)
- {
- LONG error;
-
- error = SaveBuffer(saveFile,sr,MODE_Regular);
- if(error == OK)
- Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
- else
- PrintFault(error,saveFile);
- }
-
- /* Empty the circular buffer? */
- if(ShellArguments.Empty)
- {
- EmptyFIFO(sr);
-
- Printf("Sashimi buffer cleared.\n");
- }
-
- /* Turn off Sashimi? */
- if(ShellArguments.Off)
- {
- struct Task * owner;
-
- Forbid();
-
- /* We cannot tell Sashimi to quit
- * if there is a single customer
- * left, such as us. This is why
- * we close the resource and
- * signal Sashimi to quit.
- */
- owner = sr->sr_Owner;
- CloseSashimiResource(sr);
- sr = NULL;
-
- Signal(owner,SIGBREAKF_CTRL_C);
-
- Permit();
- }
- }
-
- if(added && NOT ShellArguments.Off)
- {
- ULONG signalsReceived,signalsToWaitFor;
- BOOL done;
-
- /* Open a console window? */
- if(ShellArguments.Console)
- {
- STRPTR consoleWindow;
- LONG error = OK;
-
- if(ShellArguments.Window != NULL)
- consoleWindow = ShellArguments.Window;
- else
- consoleWindow = "CON:0/20/640/100/Sashimi [Ctrl]+E=Empty [Ctrl]+F=File [Ctrl]+D=Reset console/AUTO/CLOSE/WAIT/INACTIVE";
-
- /* Open the window and make it the default
- * I/O stream.
- */
- newInput = Open(consoleWindow,MODE_NEWFILE);
- if(newInput != ZERO)
- {
- oldConsoleTask = SetConsoleTask(((struct FileHandle *)BADDR(newInput))->fh_Type);
- newOutput = Open("CONSOLE:",MODE_OLDFILE);
- if(newOutput != ZERO)
- {
- oldInput = SelectInput(newInput);
- oldOutput = SelectOutput(newOutput);
- }
- else
- {
- error = IoErr();
-
- /* Return to the original console task. */
- SetConsoleTask(oldConsoleTask);
- oldConsoleTask = NULL;
- }
- }
- else
- {
- error = IoErr();
- }
-
- if(error != OK)
- PrintFault(error,consoleWindow);
- }
-
- /* Show the banner message. */
- if(NOT ShellArguments.NoPrompt && NOT ShellArguments.Quiet)
- {
- struct Process * cli = (struct Process *)FindTask(NULL);
- LONG maxCli,thisCli = 1,i;
-
- /* Find our current CLI process number. */
- maxCli = MaxCli();
- for(i = 1 ; i <= maxCli ; i++)
- {
- if(FindCliProc(i) == cli)
- {
- thisCli = i;
- break;
- }
- }
-
- Printf("Sashimi installed ([Ctrl]+C or \"Break %ld\" to remove)\n",thisCli);
- }
-
- GlobalSashimiResource = sr;
- InstallPatches();
-
- signalsToWaitFor = SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
- SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F |
- sr->sr_OwnerSigMask;
-
- /* Start the timer. */
- if(ShellArguments.TimerOn)
- {
- signalsToWaitFor |= (1UL << timePort->mp_SigBit);
-
- timeRequest->tr_node.io_Command = TR_ADDREQUEST;
- timeRequest->tr_time.tv_secs = 0;
- timeRequest->tr_time.tv_micro = MILLION / 10;
-
- SendIO((struct IORequest *)timeRequest);
- }
-
- done = FALSE;
- do
- {
- signalsReceived = Wait(signalsToWaitFor);
-
- /* Check if we should test the buffer. */
- if(ShellArguments.TimerOn)
- {
- if(signalsReceived & (1UL << timePort->mp_SigBit))
- {
- signalsReceived |= sr->sr_OwnerSigMask;
-
- WaitIO((struct IORequest *)timeRequest);
-
- /* Restart the timer. */
- timeRequest->tr_node.io_Command = TR_ADDREQUEST;
- timeRequest->tr_time.tv_secs = 0;
- timeRequest->tr_time.tv_micro = MILLION / 10;
-
- SendIO((struct IORequest *)timeRequest);
- }
- }
-
- /* Check if we should test the buffer. */
- if(signalsReceived & sr->sr_OwnerSigMask)
- {
- if(NOT ShellArguments.Quiet)
- {
- UBYTE localBuffer[256];
- ULONG moreSignals;
- LONG filled;
-
- /* Try to empty the circular buffer. */
- while((filled = ReadFIFOChars(sr,localBuffer,sizeof(localBuffer))) > 0)
- {
- /* Check if there is a message for us. */
- moreSignals = SetSignal(0,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
-
- /* Save the circular buffer to a file? */
- if(moreSignals & SIGBREAKF_CTRL_F)
- {
- LONG error;
-
- error = SaveBuffer(saveFile,sr,MODE_Regular);
- if(error == OK)
- Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
- else
- PrintFault(error,saveFile);
- }
-
- /* Empty the circular buffer? */
- if(moreSignals & SIGBREAKF_CTRL_E)
- {
- EmptyFIFO(sr);
-
- Printf("Sashimi buffer cleared.\n");
- filled = 0;
- }
-
- /* Stop Sashimi? */
- if(moreSignals & SIGBREAKF_CTRL_C)
- {
- signalsReceived |= SIGBREAKF_CTRL_C;
- break;
- }
-
- /* Write the buffer to the file. */
- if(filled > 0)
- Write(Output(),localBuffer,filled);
- }
- }
- }
-
- /* Save current buffer to file. */
- if(signalsReceived & SIGBREAKF_CTRL_F)
- {
- LONG error;
-
- error = SaveBuffer(saveFile,sr,MODE_Regular);
- if(error == OK)
- Printf("Sashimi buffer saved as \"%s\".\n",saveFile);
- else
- PrintFault(error,saveFile);
- }
-
- /* Empty the buffer. */
- if(signalsReceived & SIGBREAKF_CTRL_E)
- {
- EmptyFIFO(sr);
-
- Printf("Sashimi buffer cleared.\n");
- }
-
- /* Reset the terminal. */
- if(signalsReceived & SIGBREAKF_CTRL_D)
- {
- Printf("\033c");
- Flush(Output());
- }
-
- /* Terminate the program. */
- if(signalsReceived & SIGBREAKF_CTRL_C)
- {
- BOOL terminate = FALSE;
-
- if(ShellArguments.AskExit)
- {
- UBYTE buffer[4];
-
- Printf("\nSashimi: stop signal received -- really exit (y or n)? ");
- Flush(Output());
-
- buffer[0] = '\0';
-
- if(FGets(Input(),buffer,sizeof(buffer)-1) != NULL)
- {
- if(buffer[0] == 'y' || buffer[0] == 'Y')
- terminate = TRUE;
- }
- }
- else
- {
- terminate = TRUE;
- }
-
- if(terminate)
- {
- if(RemoveSashimiResource(sr) == OK)
- {
- Printf("Sashimi removed.\n");
- done = TRUE;
- }
- }
- }
- }
- while(NOT done);
-
- RemovePatches();
-
- /* Stop the timer. */
- if(ShellArguments.TimerOn)
- {
- if(CheckIO((struct IORequest *)timeRequest) == BUSY)
- AbortIO((struct IORequest *)timeRequest);
-
- WaitIO((struct IORequest *)timeRequest);
- }
-
- /* Check if we should and could save the circular buffer. */
- if(ShellArguments.AskSave && GetCharsInFIFO(sr) > 0)
- {
- UBYTE name[256];
-
- Printf("Enter name to save the buffer, or hit [Return] to cancel: ");
- Flush(Output());
-
- name[0] = '\0';
-
- if(FGets(Input(),name,sizeof(name)-1) != NULL)
- {
- LONG error;
- int i;
-
- for(i = strlen(name)-1 ; i >= 0 ; i--)
- {
- if(name[i] == '\n')
- name[i] = '\0';
- }
-
- error = SaveBuffer(name,sr,MODE_Regular);
- if(error == OK)
- Printf("Sashimi buffer saved as \"%s\".\n",name);
- else
- PrintFault(error,name);
- }
- }
-
- FreeSashimiResource(sr);
- sr = NULL;
- }
-
- result = RETURN_OK;
- }
-
- /* Close the resource, if we opened it. */
- if(opened)
- CloseSashimiResource(sr);
-
- /* Remove and free the resource if we added it. */
- if(added)
- {
- RemoveSashimiResource(sr);
- FreeSashimiResource(sr);
- }
-
- /* Clean up the timer.device interface. */
- if(timeRequest != NULL)
- {
- if(timeRequest->tr_node.io_Device != NULL)
- CloseDevice((struct IORequest *)timeRequest);
-
- DeleteIORequest((struct IORequest *)timeRequest);
- }
-
- DeleteMsgPort(timePort);
-
- /* Reset and clean up the console I/O streams. */
- if(oldOutput != ZERO)
- SelectOutput(oldOutput);
-
- if(oldInput != ZERO)
- SelectInput(oldInput);
-
- if(newOutput != ZERO)
- Close(newOutput);
-
- if(oldConsoleTask != NULL)
- SetConsoleTask(oldConsoleTask);
-
- if(newInput != ZERO)
- Close(newInput);
- }
-
- FreeArgs(rdargs);
- }
- else
- {
- PrintFault(IoErr(),"Sashimi");
-
- result = RETURN_ERROR;
- }
- }
-
- return(result);
- }
-